package com.gpj.netty.demo.bio;

import com.coremedia.iso.boxes.Container;
import com.googlecode.mp4parser.authoring.Movie;
import com.googlecode.mp4parser.authoring.Track;
import com.googlecode.mp4parser.authoring.builder.DefaultMp4Builder;
import com.googlecode.mp4parser.authoring.container.mp4.MovieCreator;
import com.googlecode.mp4parser.authoring.tracks.AppendTrack;
import com.googlecode.mp4parser.authoring.tracks.CroppedTrack;

import java.io.*;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * @className Test
 * @description TODO
 * @author GPJ
 * @date 2021/1/30 18:33
 * @version 1.0
 **/
public class VideoUtil {
	public static void main(String[] args) throws IOException {
		List<String> videoList = new ArrayList<>();
		videoList.add("F:\\录屏\\1.mp4");
		videoList.add("F:\\录屏\\2.mp4");
//		mergeVideo(videoList, new File("F:\\录屏\\new.mp4"));

		clip("F:\\录屏\\new.mp4","F:\\录屏\\result.mp4",1000, ((1 * 3600) + (44 * 60) + 3) * 1000);
	}

	public static String mergeVideo(List<String> videoList, File mergeVideoFile) {
		FileOutputStream fos = null;
		FileChannel fc = null;
		try {
			List<Movie> sourceMovies = new ArrayList<>();
			for (String video : videoList) {
				sourceMovies.add(MovieCreator.build(video));
			}

			List<Track> videoTracks = new LinkedList<>();
			List<Track> audioTracks = new LinkedList<>();

			for (Movie movie : sourceMovies) {
				for (Track track : movie.getTracks()) {
					if ("soun".equals(track.getHandler())) {
						audioTracks.add(track);
					}

					if ("vide".equals(track.getHandler())) {
						videoTracks.add(track);
					}
				}
			}

			Movie mergeMovie = new Movie();
			if (audioTracks.size() > 0) {
				mergeMovie.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));
			}

			if (videoTracks.size() > 0) {
				mergeMovie.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));
			}

			Container out = new DefaultMp4Builder().build(mergeMovie);
			fos = new FileOutputStream(mergeVideoFile);
			fc = fos.getChannel();
			out.writeContainer(fc);
			fc.close();
			fos.close();
			return mergeVideoFile.getAbsolutePath();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (fc != null) {
				try {
					fc.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		return null;
	}

	public static void clip(String srcPath, String outPath, double startTimeMs, double endTimeMs) throws IOException, IllegalArgumentException {
		Movie movie = MovieCreator.build(srcPath);
		List<Track> tracks = movie.getTracks();
		//移除旧的track
		movie.setTracks(new LinkedList<Track>());
		//处理的时间以秒为单位
		double startTime = startTimeMs/1000;
		double endTime = endTimeMs/1000;
		//计算剪切时间，视频的采样间隔大，以视频为准
		for (Track track : tracks) {
			if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) {
				startTime = correctTimeToSyncSample(track, startTime, false);
				endTime = correctTimeToSyncSample(track, endTime, true);
				if (track.getHandler().equals("vide")) {
					break;
				}
			}
		}

		long currentSample;
		double currentTime;
		double lastTime;
		long startSample1;
		long endSample1;
		long delta;

		for (Track track : tracks) {
			currentSample = 0;
			currentTime = 0;
			lastTime = -1;
			startSample1 = -1;
			endSample1 = -1;

			//根据起始时间和截止时间获取起始sample和截止sample的位置
			for (int i = 0; i < track.getSampleDurations().length; i++) {
				delta = track.getSampleDurations()[i];
				if (currentTime > lastTime && currentTime <= startTime) {
					startSample1 = currentSample;
				}
				if (currentTime > lastTime && currentTime <= endTime) {
					endSample1 = currentSample;
				}
				lastTime = currentTime;
				currentTime += (double)delta / (double)track.getTrackMetaData().getTimescale();
				currentSample++;
			}
			if (startSample1 <= 0 && endSample1 <= 0) {
				throw new RuntimeException("clip failed !!");
			}
			movie.addTrack(new CroppedTrack(track, startSample1, endSample1));// 添加截取的track
		}

		//合成视频mp4
		Container out = new DefaultMp4Builder().build(movie);
		FileOutputStream fos = new FileOutputStream(outPath);
		FileChannel fco = fos.getChannel();
		out.writeContainer(fco);
		fco.close();
		fos.close();
	}

	public static double correctTimeToSyncSample(Track track, double cutHere, boolean next) {
		double[] timeOfSyncSamples = new double[track.getSyncSamples().length];
		long currentSample = 0;
		double currentTime = 0;
		for (int i = 0; i < track.getSampleDurations().length; i++) {
			long delta = track.getSampleDurations()[i];
			int index = Arrays.binarySearch(track.getSyncSamples(), currentSample + 1);
			if (index >= 0) {
				timeOfSyncSamples[index] = currentTime;
			}
			currentTime += ((double)delta / (double)track.getTrackMetaData().getTimescale());
			currentSample++;
		}
		double previous = 0;
		for (double timeOfSyncSample : timeOfSyncSamples) {
			if (timeOfSyncSample > cutHere) {
				if (next) {
					return timeOfSyncSample;
				} else {
					return previous;
				}
			}
			previous = timeOfSyncSample;
		}
		return timeOfSyncSamples[timeOfSyncSamples.length - 1];
	}
}
